package com.wdd.myplatform.service.impl;

import com.wdd.myplatform.entity.EsDemoBean;
import com.wdd.myplatform.repository.EsGoodsRespository;
import com.wdd.myplatform.service.EsDemoService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
@Service
public class EsDemoServiceImpl implements EsDemoService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EsDemoServiceImpl.class);

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private EsGoodsRespository esGoodsRespository;


    @Override
    public EsDemoBean create(String id) {
        EsDemoBean esDemoBean = new EsDemoBean();
        esDemoBean.setUserId(id);
        esDemoBean.setSex("0");
        esDemoBean.setEmail("haha@qq.com");
        esDemoBean.setPhonenumber("17551072222");
        esDemoBean.setLoginIp("192.168.103.201");
        esDemoBean.setLoginName("wdd");
        esDemoBean.setUserName("你是猴子请来的救兵吗");
        esDemoBean.setLoginDate(new Date());
        esDemoBean.setRemark("中国青年报客户端北京4月21日电（中青报·中青网记者邱晨辉）记者从中央气象台获悉，受蒙古气旋和地面冷锋影响，4月19日至21日，我国北方地区出现一次大规模大风沙尘天气。截至20日16时，新疆北部、内蒙古中西部和东南部、辽宁中西部、吉林中西部、黑龙江西南部等地出现7～9级阵风，新疆北部局地出现11～12级阵风；新疆北部和南疆盆地、内蒙古中西部、吉林中西部、黑龙江中西部等地出现扬沙或浮尘天气，内蒙古西部出现沙尘暴。\n" +
                "据中央气象台首席预报员饶晓琴介绍，本次大风沙尘天气呈现“风力强劲、沙尘影响大”的特点，将自西向东影响我国北方大部地区，是北方入春以来最大范围大风沙尘天气过程。\n" +
                "饶晓琴解释，此次北方沙尘天气过程产生原因有两方面，一是由于蒙古气旋较为强盛，为沙源区起沙和向下游传输提供了有利的热力与动力条件；二是4月以来，蒙古国和我国西北地区、内蒙古中西部等地降水偏少、气温偏高，导致地表疏松，同时春季植被尚未恢复，沙源区下垫面条件利于起沙。据悉，今年我国已经出现3次沙尘天气过程，其中2次扬沙，1次沙尘暴过程，与常年同期相比偏少3次。今年沙尘天气过程总体呈现“首次发生时间偏晚、次数偏少、强度偏弱”的特点。\n" +
                "气象部门预计，此次沙尘天气过程预计于21日夜间结束。20日至21日，新疆东部、内蒙古、西北地区北部、华北、东北以及黄渤海区将先后有4～6级风，阵风7～9级、局地10级以上。其中内蒙古地区阵风8～10级，局地11级以上。受大风天气和沙尘传输影响，新疆东部和南疆盆地、甘肃西部、内蒙古中西部和东南部、宁夏、陕西中北部、山西中北部、河北中北部、北京、天津、吉林中西部、黑龙江中西部等地有扬沙或浮尘天气，内蒙古中西部局地有沙尘暴。21日，内蒙古中东部和东北地区自西向东有降水天气，对上述地区沙尘缓解和空气质量改善较为有利。尤其是东北地区，将出现一场“透雨”。\n" +
                "饶晓琴提示，公众需防范大风天气的不利影响，做好室外搭建物和广告牌加固、设施农业加固、户外高空作业安全防护等；针对温高雨少、大风沙尘等天气，需注意加强城市和森林防火。受沙尘天气影响，西北、华北和东北部分地区空气质量会出现短时恶化，公众需注意做好健康防护，注意携带口罩、纱巾等防尘用品，以免沙尘对眼睛和呼吸道造成损伤；沙尘天气影响期间能见度较低，需注意交通运输安全，驾驶员注意控制驾驶车速。\n" +
                "\n");
        EsDemoBean save = esGoodsRespository.save(esDemoBean);
        return save;
    }

    @Override
    public Page<EsDemoBean> search(String keyword, Integer pageNum, Integer pageSize) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        return esGoodsRespository.findByUserIdOrRemark(keyword, keyword, pageable);
    }

    @Override
    public Page<EsDemoBean> search(String keyword, Long brandId, Long productCategoryId, Integer pageNum, Integer pageSize,Integer sort) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //分页
        nativeSearchQueryBuilder.withPageable(pageable);
        //过滤
        if (brandId != null || productCategoryId != null) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if (brandId != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery("brandId", brandId));
            }
            if (productCategoryId != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery("productCategoryId", productCategoryId));
            }
            nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        }
        //搜索
        if (StringUtils.isEmpty(keyword)) {
            System.out.println("没有keyword");
            nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
        } else {
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("userName", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(10)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("remark", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(8)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("subTitle", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(5)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("keywords", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
        }
        //排序
        if(sort==1){
            //按新品从新到旧
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
        }else if(sort==2){
            //按销量从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sale").order(SortOrder.DESC));
        }else if(sort==3){
            //按价格从低到高
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
        }else if(sort==4){
            //按价格从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        }else{
            //按相关度
            nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        }
        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        LOGGER.info("DSL:{}", searchQuery.getQuery().toString());
        SearchHits<EsDemoBean> searchHits = elasticsearchRestTemplate.search(searchQuery, EsDemoBean.class);
        if(searchHits.getTotalHits()<=0){
            return new PageImpl<>(Collections.EMPTY_LIST,pageable,0);
        }
        List<EsDemoBean> searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return new PageImpl<>(searchProductList,pageable,searchHits.getTotalHits());
    }

    @Override
    public Page<EsDemoBean> recommend(String id, Integer pageNum, Integer pageSize) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        /*List<EsDemoBean> EsDemoBeanList = productDao.getAllEsDemoBeanList(id);
        if (EsDemoBeanList.size() > 0) {
            EsDemoBean EsDemoBean = EsDemoBeanList.get(0);
            String keyword = EsDemoBean.getName();
            Long brandId = EsDemoBean.getBrandId();
            Long productCategoryId = EsDemoBean.getProductCategoryId();
            //根据商品标题、品牌、分类进行搜索
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("name", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(8)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("subTitle", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("keywords", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("brandId", brandId),
                    ScoreFunctionBuilders.weightFactorFunction(5)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("productCategoryId", productCategoryId),
                    ScoreFunctionBuilders.weightFactorFunction(3)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            //用于过滤掉相同的商品
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.mustNot(QueryBuilders.termQuery("id",id));
            //构建查询条件
            NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
            builder.withQuery(functionScoreQueryBuilder);
            builder.withFilter(boolQueryBuilder);
            builder.withPageable(pageable);
            NativeSearchQuery searchQuery = builder.build();
            LOGGER.info("DSL:{}", searchQuery.getQuery().toString());
            SearchHits<EsDemoBean> searchHits = elasticsearchRestTemplate.search(searchQuery, EsDemoBean.class);
            if(searchHits.getTotalHits()<=0){
                return new PageImpl<>(null,pageable,0);
            }
            List<EsDemoBean> searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
            return new PageImpl<>(searchProductList,pageable,searchHits.getTotalHits());
        }*/
        return new PageImpl<>(null);
    }

    /**
     * 更新商品信息
     * @param id
     * @return
     */
    @Override
    public EsDemoBean update(String id) {
        EsDemoBean esDemoBean = new EsDemoBean();
        esDemoBean.setUserId(id);
        esGoodsRespository.delete(esDemoBean);
        esGoodsRespository.save(esDemoBean);
        return null;
    }

    @Override
    public List<EsDemoBean> searchList(String keyword) {
        if(StringUtils.isBlank(keyword)){
            Iterable<EsDemoBean> iterable = esGoodsRespository.findAll();
            List<EsDemoBean> list = new LinkedList<>();
            iterable.forEach(e->{
                list.add(e);
            });
            return list;
        }
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keyword));
        SearchHits<EsDemoBean> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), EsDemoBean.class);
        if(searchHits.getTotalHits() <= 0){
            return Collections.emptyList();
        }
        List<EsDemoBean> collect = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return collect;
    }
}
